package com.example.starter.mybatis.configure;

import cn.hutool.core.date.LocalDateTimeUtil;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import com.baomidou.mybatisplus.core.injector.ISqlInjector;
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor;
import com.example.starter.mybatis.anntation.CreateTime;
import com.example.starter.mybatis.anntation.CreatedBy;
import com.example.starter.mybatis.anntation.DeleteTime;
import com.example.starter.mybatis.anntation.UpdateTime;
import com.example.starter.mybatis.handler.ExampleTenantLineHandler;
import com.example.starter.mybatis.injector.ExampleSqlInjector;
import com.example.starter.security.util.SecurityUtil;
import lombok.RequiredArgsConstructor;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.lang.reflect.Field;
import java.time.LocalDateTime;
import java.util.List;

/**
 * @author 王令
 * @since 2022-05-13 09-21-21
 */
@Configuration
@RequiredArgsConstructor
@EnableConfigurationProperties(MybatisProperties.class)
public class MybatisPlusAutoConfiguration implements MetaObjectHandler {

    private final MybatisProperties properties;

    private static final LocalDateTime DEFAULT_DATE_TIME =
            LocalDateTimeUtil.parse("1970-01-01 00:00:00", "yyyy-MM-dd HH:mm:ss");

    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {

        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        //乐观锁配置
        interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
        if (properties.getMultiTenant().getEnabled()) {
            // 多租户配置
            interceptor.addInnerInterceptor(new TenantLineInnerInterceptor(new ExampleTenantLineHandler(properties)));
        }
        //分页配置
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        return interceptor;
    }

    @Bean
    public ISqlInjector exampleSqlInjector() {
        return new ExampleSqlInjector();
    }

    @Override
    public void insertFill(MetaObject metaObject) {
        final Class<?> clazz = metaObject.getOriginalObject().getClass();
        final List<Field> allFields = TableInfoHelper.getAllFields(clazz);

        LocalDateTime now = LocalDateTimeUtil.now();
        for (Field field : allFields) {
            if (field.isAnnotationPresent(CreateTime.class)) {
                this.strictInsertFill(metaObject, field.getName(), LocalDateTime.class, now);
            } else if (field.isAnnotationPresent(UpdateTime.class)) {
                this.strictInsertFill(metaObject, field.getName(), LocalDateTime.class, now);
            } else if (field.isAnnotationPresent(DeleteTime.class)) {
                this.strictInsertFill(metaObject, field.getName(), LocalDateTime.class, DEFAULT_DATE_TIME);
            } else if (field.isAnnotationPresent(CreatedBy.class)) {
                this.strictInsertFill(metaObject, field.getName(), String.class, SecurityUtil.getUsername());
            }
        }
    }

    @Override
    public void updateFill(MetaObject metaObject) {
        LocalDateTime now = LocalDateTimeUtil.now();
        final Class<?> clazz = metaObject.getOriginalObject().getClass();
        final List<Field> allFields = TableInfoHelper.getAllFields(clazz);
        for (Field field : allFields) {
            if (field.isAnnotationPresent(UpdateTime.class)) {
                this.strictUpdateFill(metaObject, field.getName(), LocalDateTime.class, now);
            }
        }
    }

}
